$LOAD_PATH.unshift File.join(File.dirname(__FILE__),'../..','ext_pr1/lib')
require 'ext_pr1_v4'
#####################################################################
# Summe
#
# Summiert alle zahlen von 1 bis n
# sum :: (LetzterSummand) ::::
# INT -> INT
# Beispiele
#  1 => 1, 2 => 3, 3 => 6
def sum(n)
   check_pre(n.int?)
   n > 0 ? n+sum(n-1) : n
end

# Endrekursiv
def sum2(n)
   check_pre(n.int?)
   sum2_(0,n)
end
def sum2_(m,n)
   n == 0 ? m : sum2_(m+n,n-1)
end

# While
def sum3(n)
   summe = 0
   while( n > 0 )
      summe+=n
      n-=1
   end
   summe
end

# Reduce
def sum4(n)
   check_pre(n.int?)
   (0..n).reduce(:+)
end


# Potenz
#
# Berechnet die n-Potenz einer Zahl x
# potenz :: (Zahl,Potenz) ::::
# NAT x NAT -> NAT
# Beispiele
# 2,1 => 2, 2,2 => 4, 2,3 => 8, 2,4 => 16
def potenz(x,n)
   check_pre((x.nat? and n.nat?))
   n > 0 ? x*potenz(x,n-1) : 1
end

# Endrekursiv
def potenz2(x,n)
   check_pre((x.nat? and n.nat?))
   potenz2_(1,x,n)
end
def potenz2_(a,x,n)
   n==0? a : potenz2_(a*x,x,n-1)
end

# While
def potenz3(x,n)
   check_pre((x.nat? and n.nat?))
   erg = 1
   while (n > 0)
      erg = x * erg
      n-=1
   end
   erg
end

# Reduce
def potenz4(x,n)
   check_pre((x.nat? and n.nat?))
   (1..n).reduce(1) {|accu,e| accu*x}
end

# Fibonacci
#
# Berechnet die n-te Fibonacci-Zahl
# fibo :: ( n ) ::::
# INT -> INT
# Beispiele
# 1=>1, 2=>1, 3=>2, 4=>3, 5=>5, 6=>8, 7=>13, 8=>21
def fibo(n)
   check_pre(n.int?)
   n > 1 ? fibo(n-1)+fibo(n-2) : n > 0 ? 1 : 0
end


#####################################################################
# Listen
class List
   # Dreht eine Liste um
   # reverse_endrec ::
   def reverse_endrec
      self.empty? ? self : self.reverse_endrec_(List[],self)
   end
   def reverse_endrec_(akku,list)
      list.empty? ? akku : self.reverse_endrec_(cons(list.first,akku),list.rest)
   end
   # Gleichheit, sonst ging der Test nicht
   def ==(list)
      self.to_a==list.to_a
   end
   # Zwei Listen zusammenf�gen
   # :+ :: list
   # LIST x LIST -> LIST
   # LIST[1]+LIST[2]->LIST[1,2]
   def +(list)
      cons(self,list)
   end
end

#####################################################################
# SETs
class Set
   def superset?(set)
       
      set.each{|e| if not self.include?(e) then return false end}
      true
    end

   def ==(o) self.equals?(o) or (o.set? and self.size == o.size and self.all?{|e| e.in?(o)}) end
   
   def ==(aSet) self.equals?(aSet) or (aSet.set? and self.superset?(aSet) and aSet.superset?(self)) end
   
   def == (o) 
       
      
   
end

#####################################################################
# Array
class Array
   def to_int
      str = ""
      self.each{|e| str << e.to_s}
      str.to_i
   end
   
   def even_only
      self.select {|e| e % 2 == 0}
   end

   def flatten
      arr = []
      self.each{|elem|
      if elem.array? then arr = arelem.flatten
      else arr << elem
      end }
      arr
   end
   
   def flatten
      res = []
      self.each{|elem| res << (not elem.array? ? elem : elem.flatten)}
      res
   end
   
   
    def flatten; reduce([]){|accu,elem| accu << (not elem.array? ? elem : elem.flatten)} end
   
 
   def no_of_leaves
      a = 0
      self.each{|e|
      if e.is_a?(Array) then
      a = a + e.no_of_leaves
      else
      a = a + 1
      end}
      a
   end
end


#####################################################################
# Hashes
class Hash
   def ==(h)
      self.size.equal?(h.size)
      a = self.to_a
      b = h.to_a
      a.all?{|e|  b.include?(e)}
   end

   def add_counts(a_hash)
      ret = {}
      self.each{  |key,value| ret.has_key?(key) ? ret[key] += self[key] : ret[key] = value}
      a_hash.each{|key,value| ret.has_key?(key) ? ret[key] += self[key] : ret[key] = value}
      ret
   end
end


#####################################################################

# Enumerable is not a Class
module Enumerable
   def to_a
      a = []
      self.each{|e| a << e}
      a
   end

   def map
      a = []
      self.each {|e| a << yield(e)}
      a
   end

   def any?
      a = false
      self.each{|e| if  yield(e) then a = true; a; end}
   end

   def max
      if block_given? then
         accu = self.first
         self.each{|word| yield(accu, word) == -1 ? accu = word : accu }
         accu
      else
         self.last
      end
   end
   
   def freq_count
      h = {}
      self.each {|buchstab|  h.include_key?(buchstab) ? h[buchstab] += 1 : h[buchstab] = 1 }
      h
   end
end
